#pragma once

#include <cstdint>
#include <vector>
#include <tuple>
#include "udp_client.h"
#include "tcp_client.h"
#include "stun_message.h"

class P2pPunch {

public:
    P2pPunch();
    P2pPunch(std::shared_ptr<UdpClient>);
    P2pPunch(P2pPunch &) = delete;
    ~P2pPunch() = default;
    
    static const int UDP_CLIENT_MAX = 400;


    int detect();
    int punch();

    int add_peer(const std::string &ip, const std::string &port, const std::string &nat);
    int add_peer(const std::string &peer);
    int add_peers(const std::vector<std::string> &&peers);
    int add_peers(const std::vector<std::string> &peers);

    void refresh_peers();

    int add_client(std::shared_ptr<UdpClient> uc){
        vuclient_.push_back(uc);
        return 0;
    }

    void init_peer_mgr() {
        peer_mgr_.local_nat_type(local_nat_type_);
    }

    void dump_peer_mgr() {
        peer_mgr_.dump();

        return ;
    }
    
    std::string locl_ref_ip() {
        return local_ref_ip_;
    }
    
    uint16_t local_ref_port() {
        return local_ref_port_;
    }

    PeerMgr &peer_mgr() {
        return peer_mgr_;
    }

    int notify_self_info(tcp_client &tc);
    int notify_self_result(tcp_client &tc);

private:

    void detect_refletive(std::string &rip, uint16_t &rport, const std::tuple<std::string, std::string> &s);

    std::string local_ref_ip_;
    uint16_t local_ref_port_;
    uint8_t local_nat_type_;
    std::vector<std::shared_ptr<UdpClient>> vuclient_;
    

    enum {STUN_MAX_SERVERS = 2};
    std::tuple<std::string, std::string> stun_servers_[STUN_MAX_SERVERS];

    PeerMgr peer_mgr_;
};